<template>
  <div ref="graph" id="graph" style="height: 100%; font-size: 7px"></div>
</template>

<script>
import './plotly-basic.min'
export default {
  name: 'Graph',
  props: ['graphData', 'day', 'resize'],
  methods: {
    mountGraph() {
      // 在index.html全局引入
      Plotly.newPlot(this.$refs.graph, [], {}, {responsive: true});
      this.$refs.graph.on('plotly_hover', this.onHoverOn)
        .on('plotly_unhover', this.onHoverOff)
        .on('plotly_relayout', this.onLayoutChange);

    },

    onHoverOn(data) {

      let curveNumber = data.points[0].curveNumber;
      let name = this.graphData.traces[curveNumber].name;

      if (name) {

        this.traceIndices = this.graphData.traces.map((e, i) => e.name === name ? i : -1).filter(e => e >= 0);
        let update = {'line': {color: 'rgba(254, 52, 110, 1)'}};

        for (let i of this.traceIndices) {
          Plotly.restyle(this.$refs.graph, update, [i]);
        }
      }

    },

    onHoverOff() {

      let update = {'line': {color: 'rgba(0,0,0,0.15)'}};

      for (let i of this.traceIndices) {
        Plotly.restyle(this.$refs.graph, update, [i]);
      }

    },

    onLayoutChange(data) {

      this.emitGraphAttributes();

      // if the user selects autorange, go back to the default range
      if (data['xaxis.autorange'] === true || data['yaxis.autorange'] === true) {
        this.userSetRange = false;
        this.updateGraph();
      }

      // if the user selects a custom range, use this
      else if (data['xaxis.range[0]']) {
        this.xrange = [data['xaxis.range[0]'], data['xaxis.range[1]']].map(e => parseFloat(e));
        this.yrange = [data['yaxis.range[0]'], data['yaxis.range[1]']].map(e => parseFloat(e));
        this.userSetRange = true;
      }

    },

    updateGraph() {

      // we're deep copying the layout object to avoid side effects
      // because plotly mutates layout on user input
      // note: this may cause issues if we pass in date objects through the layout
      let layout = JSON.parse(JSON.stringify(this.graphData.layout));

      // if the user selects a custom range, use it
      if (this.userSetRange) {
        layout.xaxis.range = this.xrange;
        layout.yaxis.range = this.yrange;
      }

      Plotly.react(this.$refs.graph, this.graphData.traces, layout, this.graphData.config);

    },

    calculateAngle() {
      if (this.graphData.uistate.showTrendLine && this.graphData.uistate.doublingTime > 0) {
        let element = this.$refs.graph.querySelector('.cartesianlayer').querySelector('.plot').querySelector('.scatterlayer').lastChild.querySelector('.lines').firstChild.getAttribute('d');
        let pts = element.split('M').join(',').split('L').join(',').split(',').filter(e => e !== '');
        let angle = Math.atan2(pts[3] - pts[1], pts[2] - pts[0]);
        return angle;
      } else {
        return NaN;
      }
    },

    emitGraphAttributes() {
      let graphOuterDiv = this.$refs.graph.querySelector('.main-svg').attributes;
      this.$emit('update:width', graphOuterDiv.width.nodeValue);
      this.$emit('update:height', graphOuterDiv.height.nodeValue);

      let graphInnerDiv = this.$refs.graph.querySelector('.xy').firstChild.attributes;
      this.$emit('update:innerWidth', graphInnerDiv.width.nodeValue);
      this.$emit('update:innerHeight', graphInnerDiv.height.nodeValue);
      this.$emit('update:referenceLineAngle', this.calculateAngle());
    }

  },

  mounted() {
    this.mountGraph();

    if (this.graphData) {
      this.updateGraph();
    }

    this.emitGraphAttributes();
    this.$emit('update:mounted', true);

  },

  watch: {

    graphData: {

      deep: true,

      handler(data, oldData) {

        // if UI state changes, revert to auto range
        if (JSON.stringify(data.uistate) !== JSON.stringify(oldData.uistate)) {
          this.userSetRange = false;
        }

        this.updateGraph();
        this.$emit('update:referenceLineAngle', this.calculateAngle());

      }

    },

    resize() {
      Plotly.Plots.resize(this.$refs.graph);
    },

  },

  data() {
    return {
      xrange: [], // stores user selected xrange
      yrange: [], // stores user selected yrange
      userSetRange: false, // determines whether to use user selected range
      traceIndices: [],
    };
  }
};
</script>

<style scoped>

</style>
